import json
import time
from urllib.parse import urlparse
import requests
from enums.topic_view_status_enum import TopicViewStatusEnum
from enums.work_order_status_enum import WorkOrderStatusEnum
from utils.common.scheduler import scheduler
from utils.commit.submit_wjx_v2 import do_submit, convert_data_to_submit_data
import model.model as ut
from dao import work_order_dao, topic_dao, work_order_extend_dao, strategy_dao
import datetime
import random
import view.submit as v_submit
from exception.api_exception import APIException
from utils.common.init_app import app
import traceback
import env_config


def send_results(work_order_id: int, ids: [], item_answer_start: int, item_answer_end: int, title_link: str,
                 area_value_weight_dict: dict):
    """
    发送数据 - 若开始则不能停止发送
    :param work_order_id: 工单id
    :param ids: 需要处理的数据库id
    :param item_answer_start: 一行数据的答题开始时间
    :param item_answer_end: 一行数据的答题结束时间
    :param title_link: 问卷的链接
    :param area_value_weight_dict: 区域权重的字典
    :return: 发送后的结果数据
    """

    def update_topic_info(item_topic: ut.Topic, status: int, submit_start_time, submit_end_time, request_res,
                          request_ip):
        """
        更新当前数据提交后的结果状态
        :param item_topic:
        :param status:
        :param submit_start_time: 提交开始时间
        :param submit_end_time: 提交结束时间
        :param request_res: 请求结果
        :param request_ip: 请求的ip地址
        :return:
        """
        item_topic.submitted = status
        item_topic.submit_start_time = submit_start_time
        item_topic.submit_end_time = submit_end_time
        item_topic.request_res = request_res
        item_topic.request_ip = request_ip
        topic_dao.batch_update_by_id([item_topic])
        return

    def send_item(data_id: int, data_id_values: ut.Topic, send_data, sleep_time: int, db_title_arr,
                  send_title_link, this_work_order_id: int, send_random_area: str, send_times: int):
        """
        发送每一条数据
        :param data_id: 这条数据在数据库中的id
        :param data_id_values: 这条数据在数据库中的对象
        :param send_data: 需要发送的数据
        :param sleep_time: 需要暂停的时间
        :param db_title_arr: 问卷所有标题对应的数据库中的标题内容
        :param send_title_link: 问卷的链接
        :param this_work_order_id: 工单id
        :param send_random_area: 标准区域的编码，全国是all
        :param send_times: 发送次数 大于等于3，则发送失败
        :return:
        """
        with app.app_context():
            # 1. 组装文件发送数据
            # 2. 发送问卷
            if send_times >= 3:  # 自动重试默认发送3次
                update_topic_info(data_id_values, -1, int(time.time()), int(time.time()), '重试超过3次', "")
                return
            else:
                t_start = int(time.time())
                send_success = False
                try:
                    submit_data = convert_data_to_submit_data(db_title_arr, json.loads(send_data))
                    request_res, ip_res = do_submit(send_random_area, send_title_link, submit_data, sleep_time)
                    # 3. 修改这一批次的数据状态为2（发送完成）
                    t_end = int(time.time())
                    request_res = request_res if len(request_res) < 510 else request_res[0:510]
                    if request_res.startswith('10〒'):  # 以10开头表示请求成功, 其余的表示请求失败
                        update_topic_info(data_id_values, 2, t_start, t_end, request_res, ip_res)
                        send_success = True
                    # else:
                    # update_topic_info(data_id_values, -1, t_start, t_end, request_res, ip_res)
                    # 发送失败，则变为发送中的状态，等待重新发送
                    # update_topic_info(data_id_values, 1, t_start, t_end, request_res, ip_res)
                except Exception as e:
                    traceback.print_exc()
                    # update_topic_info(data_id_values, -1, t_start, int(time.time()), str(e), "")
                    # 发送失败，则变为发送中的状态，等待重新发送
                    # update_topic_info(data_id_values, 1, t_start, int(time.time()), str(e), "")
                finally:
                    if not send_success:
                        print('发送失败，自动重试；重试第', send_times, '次')
                        # 运行时间
                        resend_time_unix = datetime.datetime.now() + datetime.timedelta(milliseconds=1000)
                        resend_time = resend_time_unix.strftime("%Y-%m-%d %H:%M:%S.%f")  # 生成每组数据的间隔时间(秒)
                        # resend+根据时间戳(ms)作为唯一表示
                        resend_task_id = 'resend' + str(work_order_id) + '_child_' + str(int(time.time() * 1000))
                        # 若发送失败，则重新发送
                        send_times += 1
                        scheduler.add_job(send_item, 'date', run_date=resend_time, id=resend_task_id,
                                          jobstore='default',
                                          args=(data_id, data_id_values, send_data, sleep_time, db_title_arr,
                                                send_title_link, this_work_order_id, send_random_area, send_times))
                    else:
                        # 查询工单是否全部发送完成-发送完成则置为发送成功
                        b_res, status_obj = search_send_status(this_work_order_id)
                        if b_res and status_obj.get('total') == status_obj.get('finished'):
                            work_order_dao.modify_work_order_status(work_order_id, WorkOrderStatusEnum.FINISHED.value)
            return

    def send_item_v2(data_id: int, data_id_values: ut.Topic, send_data, sleep_time: int, db_title_arr,
                     send_title_link, this_work_order_id: int, send_random_area: str):
        """
        发送每一条数据
        :param data_id: 这条数据在数据库中的id
        :param data_id_values: 这条数据在数据库中的对象
        :param send_data: 需要发送的数据
        :param sleep_time: 需要暂停的时间
        :param db_title_arr: 问卷所有标题对应的数据库中的标题内容
        :param send_title_link: 问卷的链接
        :param this_work_order_id: 工单id
        :param send_random_area: 标准区域的编码，全国是all
        :return:
        """
        with app.app_context():
            # 1. 组装文件发送数据
            # 2. 发送问卷
            be_sending = True
            count = 0  # 发送次数
            err_str = ''
            while be_sending:
                t_start = int(time.time())
                if count >= 5:
                    # 发送次数大于5次，则表示发送失败
                    update_topic_info(data_id_values, -1, t_start, int(time.time()), err_str, "")
                try:
                    submit_data = convert_data_to_submit_data(db_title_arr, json.loads(send_data))
                    request_res, ip_res = do_submit(send_random_area, send_title_link, submit_data, sleep_time)
                    # 3. 修改这一批次的数据状态为2（发送完成）
                    t_end = int(time.time())
                    request_res = request_res if len(request_res) < 510 else request_res[0:510]
                    if request_res.startswith('10〒'):  # 以10开头表示请求成功, 其余的表示请求失败
                        update_topic_info(data_id_values, 2, t_start, t_end, request_res, ip_res)
                        be_sending = False  # 发送成功，不需要再次发送
                except Exception as e:
                    print('发送失败, 第', count, '次')
                    traceback.print_exc()
                    err_str = str(e)
                finally:
                    count += 1  # 发送次数+1
            # 查询工单是否全部发送完成-发送完成则置为发送成功
            b_res, status_obj = search_send_status(this_work_order_id)
            if b_res and status_obj.get('total') == status_obj.get('finished'):
                work_order_dao.modify_work_order_status(work_order_id, WorkOrderStatusEnum.FINISHED.value)
            return

    def batch_update_status(data_item_list: [ut.Topic], status: int):
        """

        :param data_item_list:
        :param status:
        :return:
        """
        for cur_i in data_item_list:
            cur_i.submitted = status
        topic_dao.batch_update_by_id(data_item_list)
        return

    with app.app_context():
        # 1。查询这一批次需要的数据
        data_items = []
        # print('一共有多少个ids', len(ids))
        for i in ids:
            item = topic_dao.search_by_id(i)
            if item is not None:
                data_items.append(item)
        if len(data_items) <= 0:  # 数据不存在，无法进行操作
            return
        # 根据数据库数据组装结果数据
        id_data_dict = dict()
        for i in data_items:
            id_data_dict[i.id] = i

        # 查询提交数据与生成数据的映射关系
        wo_extend = work_order_extend_dao.search_by_work_order_id(work_order_id)
        if not wo_extend:
            return
        db_title_arr = wo_extend.title_maps
        # 随机值
        keys = list(area_value_weight_dict.keys())
        weights = list(area_value_weight_dict.values())
        # 2。提交这一批次的数据
        for k in id_data_dict:
            choice_arr = random.choices(keys, weights=weights, k=len(ids))
            if choice_arr:
                random_area = choice_arr[0]
            else:  # 如果生成失败则为全国
                random_area = 'all'
            time.sleep(0.002)  # 睡2毫秒，防止生成相同的task_id
            task_id = str(work_order_id) + '_child_' + str(int(time.time() * 1000))  # 根据时间戳(ms)作为唯一表示
            # print('当前child的task_id:', task_id)
            a = datetime.datetime.now() + datetime.timedelta(milliseconds=100)
            run_time = a.strftime("%Y-%m-%d %H:%M:%S.%f")  # 生成每组数据的间隔时间(秒)
            # print('当前child的每组间隔时间', run_time)
            # 查询基础数据
            # 内部任务立即执行
            random_int = random.randint(item_answer_start, item_answer_end)  # 每行数据生成一个随机数，代表这行数据需要这么多秒后再发送
            scheduler.add_job(send_item, 'date', run_date=run_time, id=task_id, jobstore='default',
                              args=(k, id_data_dict[k], id_data_dict[k].data, random_int, db_title_arr, title_link,
                                    work_order_id, random_area, 0))
        # 3。修改这一批次的数据状态为1（发送中）
        batch_update_status(data_items, 1)
        return


def search_task_status(work_order_id: int):
    """
    查询当前工单的任务状态
    :param work_order_id: 工单id
    :return:
    """
    jobs = scheduler.get_jobs()
    res = []
    for job in jobs:
        res.append(
            # {'id': job.id, 'job_next_run_time': job.next_run_time, 'pending': job.pending, 'trigger': job.trigger}
            {'id': job.id}
        )
    return res


def logs(work_order_id: int):
    """
    查询当前工单每一条数据的提交状态
    :param work_order_id:
    :return:
    """
    item = work_order_dao.query_work_order_by_id(work_order_id)
    if not item:
        raise APIException(message="当前工单不存在")
    if not item.status or item.status <= 3:
        raise APIException(message="当前工单尚未开始发送，暂无日志", code=200)
    try:
        min_time, max_time = 1893427199000, 0
        topics = topic_dao.search_by_work_order_id_status(work_order_id=work_order_id)
        res = []
        for i in topics:
            cur_status = i.submitted
            cur_status_zh = "未发送"
            if cur_status == 1:
                cur_status_zh = "发送中"
            elif cur_status == 2:
                cur_status_zh = "已发送"
            elif cur_status == -1:
                cur_status_zh = "发送失败"
            res.append({'id': i.id, 'submitted': cur_status, 'cur_status_zh': cur_status_zh,
                        'submit_start_time': i.submit_start_time, 'submit_end_time': i.submit_end_time,
                        'request_res': i.request_res, 'request_ip': i.request_ip})
            if i.submit_start_time:
                min_time = min_time if min_time < i.submit_start_time else i.submit_start_time
            if i.submit_end_time:
                max_time = max_time if max_time > i.submit_end_time else i.submit_end_time
    except Exception as e:
        traceback.print_exc()
        raise APIException(message="查询日志失败")
    return {'min_time': min_time, 'max_time': max_time, 'list': res}


def search_send_status(work_order_id: int):
    """
    查询发送状态
    :param work_order_id:
    :return:
    """
    item = work_order_dao.query_work_order_by_id(work_order_id)
    if item is None:
        return False, "工单不存在"
    topics = topic_dao.search_by_work_order_id(work_order_id)
    total = len(topics)
    if total <= 0:
        return False, "没有需要提交的数据"
    finished = 0
    sending = 0
    waiting = 0
    failed = 0
    for i in topics:
        if i.submitted == 0:
            waiting += 1
        elif i.submitted == 1:
            sending += 1
        elif i.submitted == 2:
            finished += 1
        elif i.submitted == -1:
            failed += 1
    res = {'status': item.status, 'total': total, 'finished': finished, 'sending': sending, 'waiting': waiting,
           'failed': failed}
    return True, res


def task_stop(work_order_id: int):
    """
    通过任务id停止任务进行
    :param work_order_id:
    :return:
    """
    # 1。查询工单是否存在
    item = work_order_dao.query_work_order_by_id(work_order_id)
    if item is None:
        raise APIException(message="工单不存在")
    # 2。查询还未开始的运行定时任务
    jobs = scheduler.get_jobs()
    job_ids = [job.id for job in jobs]
    prefix = str(work_order_id) + '_'
    filtered_strings = list(filter(lambda s: s.startswith(prefix), job_ids))
    # 3。删除未运行的定时任务
    for i in filtered_strings:
        scheduler.remove_job(i)
    work_order_dao.modify_work_order_status(item.id, 4)
    return filtered_strings


def tasks():
    jobs = scheduler.get_jobs()
    return jobs


def task_stop_v2(work_order_id: int):
    """
    通过任务id停止任务进行
    :param work_order_id:
    :return:
    """
    # 1。查询工单是否存在
    item = work_order_dao.query_work_order_by_id(work_order_id)
    if item is None:
        raise APIException(message="工单不存在")
        # 发送到定时任务到任务系统执行定时任务
    # url = 'http://192.168.1.6:5003/api/v1/stop_send_result'
    env_mp = env_config.config_mapping()
    url = env_mp.get('SEND_TASK_URL') + '/api/v1/stop_send_result'
    header = {'Content-Type': 'application/json'}
    data = {'work_order_id': work_order_id}
    response = requests.Session().post(url=url, headers=header, json=data)
    res = "任务停止失败"
    if response and response.status_code == 200:
        res = "任务已停止"
    return res


def task_finished_time(obj: v_submit.JudgeSendDate):
    """

    :param params:
    :return:
    """
    res = ''
    work_order_id = obj.work_order_id  # 工单id
    item = work_order_dao.query_work_order_by_id(id=work_order_id)
    if item is None:
        raise APIException(message="工单不存在，不知道共需要发送的条数，无法测算")
    # 查询未提交的数据还有多少条
    cur_list = topic_dao.search_results_with_status(work_order_id=work_order_id,
                                                    view_status=TopicViewStatusEnum.UN_SUBMIT.value)
    total_count = len(cur_list)  # 当前的问卷的总提交数
    if total_count <= 0:
        res = '需要发送的条数为0'
        return res
    is_fast_order = obj.is_fast_order  # 是否极速提交
    item_answer_start = obj.item_answer_start  # 一行数据的答题开始时间
    item_answer_end = obj.item_answer_end  # 一行数据的答题结束时间
    deal_time_min = obj.deal_time_min  # 单次答题-最少答题个数
    deal_time_max = obj.deal_time_max  # 单次答题-最多答题个数
    interval_start = obj.interval_start  # 最小间隔答题时间
    interval_end = obj.interval_end  # 最大间隔答题时间
    can_answer_start = obj.can_answer_start  # 每天可以答题的开始时间
    can_answer_end = obj.can_answer_end  # 每天可以答题的结束时间
    if item_answer_end < item_answer_start or deal_time_max < deal_time_min or interval_end < interval_start:
        return "参数错误"

    send_count_arr = []  # 每一次能发送的数据条数
    cur_index = 0
    total_count_arr = [total_count * 1]
    while total_count > 0:
        deal_count = random.randint(deal_time_min, deal_time_max) if total_count > deal_time_min else total_count
        item_ids = total_count_arr[cur_index:cur_index + deal_count]
        send_count_arr.append(item_ids)
        total_count -= deal_count
        cur_index += deal_count
    if is_fast_order:  # 默认3秒发送5个题目，开始时间为现在
        start_time = datetime.datetime.now()
        for i in range(len(send_count_arr)):
            # 根据 interval_start 和 interval_end生成一个随机时间
            start_time = start_time + datetime.timedelta(seconds=random.randint(interval_start, interval_end))
        res = '提交模式：极速提交，预计完成时间：' + start_time.strftime('%Y-%m-%d %H:%M:%S')
    else:
        # 1.判断当前时间是否在当天可发送的时间范围内，
        # 如果小于可发送时间，则开始时间为当天的发送时间
        # 如果大于可发送时间，则从明天开始发送
        ymd = datetime.datetime.now().strftime("%Y-%m-%d")  # 当前时间的年月日
        cas_fmt_time = ymd + ' ' + datetime.datetime.fromtimestamp(can_answer_start / 1000).strftime("%H:%M:%S")
        cae_fmt_time = ymd + ' ' + datetime.datetime.fromtimestamp(can_answer_end / 1000).strftime("%H:%M:%S")
        dt_now = datetime.datetime.now()
        dt_cas = datetime.datetime.strptime(cas_fmt_time, '%Y-%m-%d %H:%M:%S')  # 可发送的开始时间
        dt_cae = datetime.datetime.strptime(cae_fmt_time, '%Y-%m-%d %H:%M:%S')  # 可发送的结束时间
        if can_answer_end <= can_answer_start:  # 如果结束时间小于等于开始时间
            dt_cae = dt_cae + datetime.timedelta(days=1)
        start_time = dt_now
        if dt_now < dt_cas:  # 如果小于可发送时间，则开始时间为当天的发送时间
            start_time = dt_cas
        elif dt_cas < dt_now < dt_cae:
            pass
        elif dt_now > dt_cae:
            start_time = dt_cas + datetime.timedelta(days=1)  # 如果大于可发送时间，则从明天开始发送
            dt_cas = start_time
            dt_cae = dt_cae + datetime.timedelta(days=1)
        else:
            start_time = dt_now

        start_time = start_time + datetime.timedelta(seconds=3)  # 3秒后开始执行第一个任务
        for i in range(len(send_count_arr)):
            # 根据 interval_start 和 interval_end生成一个随机时间
            random_int = random.randint(interval_start, interval_end)
            start_time = start_time + datetime.timedelta(seconds=random_int)
            if start_time > dt_cae:
                dt_cas = dt_cas + datetime.timedelta(days=1) + datetime.timedelta(
                    microseconds=random.randint(100000, 999999))  # 开始日期+1天
                dt_cae = dt_cae + datetime.timedelta(days=1)  # 结束日期+1天
                start_time = dt_cas  # 下次开始时间设置为明天第一时刻
        res = '提交模式：普通提交，预计完成时间：' + start_time.strftime('%Y-%m-%d %H:%M:%S')
    return res


def task_waited_send(work_order_id: int):
    # 1。查询工单是否存在
    item = work_order_dao.query_work_order_by_id(work_order_id)
    if item is None:
        raise APIException(message="工单不存在")
    if item.status == WorkOrderStatusEnum.WAITED_SEND.value:
        raise APIException(message="工单处于待发送状态，无法修改哦")
    try:
        work_order_dao.modify_work_order_status(work_order_id, WorkOrderStatusEnum.WAITED_SEND.value)
    except Exception:
        raise APIException(message="修改工单状态失败")
    return "工单已置为待发送"


def task_finished(work_order_id: int):
    # 1。查询工单是否存在
    item = work_order_dao.query_work_order_by_id(work_order_id)
    if item is None:
        raise APIException(message="工单不存在")
    if item.status == WorkOrderStatusEnum.SENDING.value:
        raise APIException(message="工单正在发送中，请先停止工单发送")
    # # 2。查询还未开始的运行定时任务
    # jobs = scheduler.get_jobs()
    # job_ids = [job.id for job in jobs]
    # prefix = str(work_order_id) + '_'
    # filtered_strings = list(filter(lambda s: s.startswith(prefix), job_ids))
    # # 3。删除未运行的定时任务
    # for i in filtered_strings:
    #     scheduler.remove_job(i)
    # 4.修改状态为已完成
    work_order_dao.modify_work_order_status(work_order_id, WorkOrderStatusEnum.FINISHED.value)
    return


def build_tasks(json_data: json, obj: v_submit.SendResults, topic_view_status: int):
    """
    参数说明
    1.答题时间：问卷打开到提交的总时间（每一份问卷的答题时间） - 默认60-120
    2.连续处理次数：同一时间能发送多少行数据 - 8-12题 / 5秒内随机发送
    3.暂停时间：每批次数据打开的间隔时间 - 默认100-200秒
    {
        "work_order_id":3, # 工单id
        "submit_type": "string", # 提交类型 -微信，浏览器...
        "item_answer_start": 0, # 一份问卷的答题开始时间
        "item_answer_end": 0, # 一份问卷的答题结束时间
        "deal_time_min": 0, # 单次答题-最少答题个数
        "deal_time_max": 0, # 单次答题-最多答题个数
        "interval_start": "string", # 最小间隔答题时间
        "interval_end": "string", # 最大间隔答题时间
        "can_answer_start": # 当天可以答题的开始时间
        "can_answer_end": # 当天可以答题的结束时间
        "is_base_order": true, # 是否乱序提交
        "area_rates": [ # 指定提交的区域
            {
                "country": "string",
                "province": "string",
                "city": "string",
                "rate": 0
            }
        ]
    }
    :return:
    """
    work_order_id = obj.work_order_id  # 工单id
    is_base_order = obj.is_base_order  # 是否乱序提交
    item_answer_start = obj.item_answer_start  # 一行数据的答题开始时间
    item_answer_end = obj.item_answer_end  # 一行数据的答题结束时间
    deal_time_min = obj.deal_time_min  # 单次答题-最少答题个数
    deal_time_max = obj.deal_time_max  # 单次答题-最多答题个数
    interval_start = obj.interval_start  # 最小间隔答题时间
    interval_end = obj.interval_end  # 最大间隔答题时间
    region_form_values = obj.regionFormValues  # 提交的区域
    # 配置区域的权重
    area_value_weight_dict = dict()
    if region_form_values:
        for i in region_form_values:
            weight = i.get('rate')
            if i.get('city'):
                area_value_weight_dict[i.get('city')] = weight
            elif i.get('province'):
                area_value_weight_dict[i.get('province')] = weight
            else:
                area_value_weight_dict['all'] = weight
    else:
        area_value_weight_dict['all'] = 1
    # 查询工单是否存在
    item = work_order_dao.query_work_order_by_id(id=work_order_id)
    if item is None:
        raise APIException(message="工单不存在，无法发起提交")
    if item.status >= 5 and TopicViewStatusEnum.UN_SUBMIT.value == topic_view_status:
        raise APIException(message="工单正在发送中或已完成，无法发起提交")
    # 存储这次发送的配置
    try:
        save_submit_config(work_order_id, json_data)
    except Exception as e:
        traceback.print_exc()
    # 查询工单需要提交的数据
    cur_list = topic_dao.search_results_with_status(work_order_id=work_order_id, view_status=topic_view_status)
    if topic_view_status == 3:
        # 重新发送的场景下，将所有发送失败的数据重置为待发送
        for cur_item in cur_list:
            cur_item.submitted = 0
        topic_dao.batch_update_by_id(cur_list)

    total_count = len(cur_list)  # 当前的问卷的总提交数
    print('需要提交的总行数', total_count)
    if total_count <= 0:
        raise APIException(message="需要发送的总数为0，暂时无法发起提交")
    # 修改当前工单状态为发送中，不能再次发送
    if item.status != WorkOrderStatusEnum.SENDING.value:
        work_order_dao.modify_work_order_status(item.id, WorkOrderStatusEnum.SENDING.value)
    # 处理提交数据
    ids = [i.id for i in cur_list]
    if is_base_order:
        random.shuffle(ids)

    # 生成任务数量及对应需要发送数据的数据库id
    send_count_arr = []  # 每一次能发送的数据条数
    cur_index = 0
    while total_count > 0:
        deal_count = random.randint(deal_time_min, deal_time_max) if total_count > deal_time_min else total_count
        item_ids = ids[cur_index:cur_index + deal_count]
        send_count_arr.append(item_ids)
        total_count -= deal_count
        cur_index += deal_count
    print('send_count_arr的长度为：', len(send_count_arr))

    title_link = item.link
    # 动态生成任务
    task_id_arr = []
    cur_time = datetime.datetime.now() + datetime.timedelta(seconds=1)  # 1秒后开始执行第一个任务
    for i in range(len(send_count_arr)):
        # time.sleep(0.002)  # 睡2毫秒，防止生成相同的task_id
        run_time = cur_time.strftime("%Y-%m-%d %H:%M:%S.%f")  # 生成每组数据的间隔时间(秒)
        task_id = str(work_order_id) + '_' + str(run_time)  # 根据时间戳(ms)作为唯一表示
        task_id_arr.append(task_id)
        print('每组任务的运行时间：', run_time)
        # 添加定时任务，并分组
        scheduler.add_job(send_results, 'date', run_date=run_time, id=task_id, jobstore='default',
                          args=(work_order_id, send_count_arr[i], item_answer_start, item_answer_end, title_link,
                                area_value_weight_dict))
        # 根据 interval_start 和 interval_end生成一个随机时间
        random_int = random.randint(interval_start, interval_end)
        cur_time = cur_time + datetime.timedelta(seconds=random_int)
    return {"title": '定时任务已启动'}


def build_tasks_v2(json_data: json, obj: v_submit.SendResults, topic_view_status: int):
    """
    参数说明
    1.答题时间：问卷打开到提交的总时间（每一份问卷的答题时间） - 默认60-120
    2.连续处理次数：同一时间能发送多少行数据 - 8-12题 / 5秒内随机发送
    3.暂停时间：每批次数据打开的间隔时间 - 默认100-200秒
    {
        "work_order_id":3, # 工单id
        "submit_type": "string", # 提交类型 -微信，浏览器...
        "item_answer_start": 0, # 一份问卷的答题开始时间
        "item_answer_end": 0, # 一份问卷的答题结束时间
        "deal_time_min": 0, # 单次答题-最少答题个数
        "deal_time_max": 0, # 单次答题-最多答题个数
        "interval_start": "string", # 最小间隔答题时间
        "interval_end": "string", # 最大间隔答题时间
        "can_answer_start": # 当天可以答题的开始时间
        "can_answer_end": # 当天可以答题的结束时间
        "is_base_order": true, # 是否乱序提交
        "is_fast_order": true, # 是否极速提交
        "area_rates": [ # 指定提交的区域
            {
                "country": "string",
                "province": "string",
                "city": "string",
                "rate": 0
            }
        ]
    }
    :return:
    """
    work_order_id = obj.work_order_id  # 工单id
    is_base_order = obj.is_base_order  # 是否乱序提交
    is_fast_order = obj.is_fast_order  # 是否极速提交
    item_answer_start = obj.item_answer_start  # 一行数据的答题开始时间
    item_answer_end = obj.item_answer_end  # 一行数据的答题结束时间
    deal_time_min = obj.deal_time_min  # 单次答题-最少答题个数
    deal_time_max = obj.deal_time_max  # 单次答题-最多答题个数
    interval_start = obj.interval_start  # 最小间隔答题时间
    interval_end = obj.interval_end  # 最大间隔答题时间
    can_answer_start = obj.can_answer_start  # 每天可以答题的开始时间
    can_answer_end = obj.can_answer_end  # 每天可以答题的结束时间

    if is_fast_order:
        # 极速提交,每批提交5个，3秒钟提交一批 -> 1分钟能提交5*60/3 = 100个（不报错的情况下）
        deal_time_min = 2
        deal_time_max = 3
        interval_start = 12
        interval_end = 25
    region_form_values = obj.regionFormValues  # 提交的区域
    # 配置区域的权重
    area_value_weight_dict = dict()
    if region_form_values:
        for i in region_form_values:
            weight = i.get('rate')
            if i.get('city'):
                area_value_weight_dict[i.get('city')] = weight
            elif i.get('province'):
                area_value_weight_dict[i.get('province')] = weight
            else:
                cur_country = i.get('country')
                if '868686' == str(cur_country):  # 中国的编码，转换成all，品赞的中国是all
                    area_value_weight_dict['all'] = weight
                else:
                    area_value_weight_dict[cur_country] = weight
    else:
        area_value_weight_dict['all'] = 1
    # 查询工单是否存在
    item = work_order_dao.query_work_order_by_id(id=work_order_id)
    if item is None:
        raise APIException(message="工单不存在，无法发起提交")
    if item.status >= 5 and TopicViewStatusEnum.UN_SUBMIT.value == topic_view_status:
        raise APIException(message="工单正在发送中或已完成，无法发起提交")
    # 存储这次发送的配置
    try:
        save_submit_config(work_order_id, json_data)
    except Exception as e:
        traceback.print_exc()
    # 查询工单需要提交的数据
    cur_list = topic_dao.search_results_with_status(work_order_id=work_order_id, view_status=topic_view_status)
    total_count = len(cur_list)  # 当前的问卷的总提交数
    app.logger.info('需要提交的总行数' + str(total_count))
    if total_count <= 0:
        raise APIException(message="需要发送的总数为0，暂时无法发起提交")
    if topic_view_status == 3:
        # 重新发送的场景下，将所有发送失败的数据重置为待发送
        for cur_item in cur_list:
            cur_item.submitted = 0
        topic_dao.batch_update_by_id(cur_list)

    # 修改当前工单状态为发送中，不能再次发送
    if item.status != WorkOrderStatusEnum.SENDING.value:
        work_order_dao.modify_work_order_status(item.id, WorkOrderStatusEnum.SENDING.value)
    # 处理提交数据
    ids = [i.id for i in cur_list]
    if is_base_order:
        random.shuffle(ids)

    # 生成任务数量及对应需要发送数据的数据库id
    send_count_arr = []  # 每一次能发送的数据条数
    cur_index = 0
    while total_count > 0:
        deal_count = random.randint(deal_time_min, deal_time_max) if total_count > deal_time_min else total_count
        item_ids = ids[cur_index:cur_index + deal_count]
        send_count_arr.append(item_ids)
        total_count -= deal_count
        cur_index += deal_count
    print('send_count_arr的长度为：', len(send_count_arr))

    title_link = item.link
    # 发送到定时任务到任务系统执行定时任务
    # url = 'http://192.168.1.6:5003/api/v1/start_task_wjx'
    env_mp = env_config.config_mapping()
    if title_link.startswith('https://www.wenjuan.com'):  # 问卷网
        url = env_mp.get('SEND_TASK_URL') + '/api/v1/start_task_wjw'
    elif title_link.startswith('https://wj.qq.com'):  # 腾讯问卷
        url = env_mp.get('SEND_TASK_URL') + '/api/v1/start_task_tx'
    elif title_link.startswith('https://docs.google.com'):  # 谷歌问卷
        url = env_mp.get('SEND_TASK_URL') + '/api/v1/start_task_gg'
    elif 'qualtrics' in title_link or 'q.surveys.' in title_link:  # qualtrics问卷
        url = env_mp.get('SEND_TASK_URL') + '/api/v1/start_task_qualtrics'
    elif 'credamo.com' in title_link:  # 见数
        url = env_mp.get('SEND_TASK_URL') + '/api/v1/start_task_credamo'
    else:  # 默认问卷星
        url = env_mp.get('SEND_TASK_URL') + '/api/v1/start_task_wjx'
    header = {'Content-Type': 'application/json'}
    data = {
        'work_order_id': work_order_id,
        'send_count_arr': send_count_arr,
        'item_answer_start': item_answer_start,
        'item_answer_end': item_answer_end,
        'interval_start': interval_start,
        'interval_end': interval_end,
        'area_value_weight_dict': area_value_weight_dict,
        'link': title_link,
        'is_fast_order': is_fast_order,
        'can_answer_start': can_answer_start,
        'can_answer_end': can_answer_end
    }
    response = requests.Session().post(url=url, headers=header, json=data)
    if response and response.status_code == 200:
        pass
    return {"title": '定时任务已启动'}


def save_submit_config(wo_id, json_obj):
    """
    保存提交相关的配置
    :return:
    """
    try:
        item = strategy_dao.search_by_work_order_id(wo_id)
        if not item:
            objs = [ut.Strategy(work_order_id=wo_id, submit_config=json_obj)]
            strategy_dao.batch_insert(objs)
        else:
            strategy_dao.modify_submit_config_by_work_order_id(wo_id=wo_id, submit_config=json_obj)
    except Exception:
        traceback.print_exc()
        raise APIException(message="保存提交相关的配置失败")
    return
